﻿using EasyNetQ;
using FluentValidation.AspNetCore;
using MuXue.Zyiz.Template.Domain.Configurations;
using MuXue.Zyiz.Template.Domain.Validators;
using MuXue.Zyiz.Template.Infrastructure;
using MuXue.Zyiz.Template.Service;
using MuXue.Zyiz.Template.Service.Impl;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Swashbuckle.AspNetCore.Swagger;
using Microsoft.OpenApi.Models;
using MuXue.Zyiz.Template.OuterClient;
using Consul;
using System.Threading;

namespace MuXue.Zyiz.Template.WebApi.Extensions
{
    public static class IServiceCollectionExtensions
    {
        /// <summary>
        /// 通用的组件
        /// </summary>
        /// <param name="services"></param>
        /// <param name="env"></param>
        /// <returns></returns>
        public static IServiceCollection AddBaseMVC(this IServiceCollection services, IWebHostEnvironment env)
        {
            services.AddMvc(options =>
            {
                if (!env.IsDevelopment())
                {
                    AuthorizationPolicy policy = new AuthorizationPolicyBuilder(
                        JwtBearerDefaults.AuthenticationScheme,
                        "Identity")
                        .RequireAuthenticatedUser()
                        .Build();
                    options.Filters.Add(new AuthorizeFilter(policy));
                }
            })
                    .SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
                    .AddJsonOptions(options => options.JsonSerializerOptions.IgnoreNullValues = true)
                    .ConfigureApiBehaviorOptions(options => options.SuppressMapClientErrors = false)
                    //model验证控件
                    .AddFluentValidation(config =>
                    {
                        config.ImplicitlyValidateChildProperties = true;
                        config.RegisterValidatorsFromAssemblyContaining<OrderListSearchReqValidator>();
                    });

            return services;
        }

        /// <summary>
        /// Service层注册
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddInjection(this IServiceCollection services)
        {
            Assembly assembly = Assembly.Load("MuXue.Zyiz.Template.Service");
            List<Type> list = assembly.GetTypes().Where(u => u.IsClass && !u.IsAbstract && !u.IsGenericType).ToList();
            foreach (var type in list)
            {
                var interfaceList = type.GetInterfaces();
                if (interfaceList.Any())
                {
                    services.AddTransient(interfaceList.First(), type);
                }
            }
             
            return services;
        }


        /// <summary>
        /// 数据库连接配置
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <returns></returns>
        public static IServiceCollection AddZyizDbContext(this IServiceCollection services, IConfiguration configuration)
        {
            return services.AddDbContextPool<IDbContext, ApplicationDbContext>(options =>
             {
                 options.UseSqlServer(configuration.GetConnectionString("zyiz"), sqlOptions =>
                 {
                     sqlOptions.EnableRetryOnFailure(3, TimeSpan.FromSeconds(30), new[] { 2 });
                 });
             }, 100);

        }

        /// <summary>
        /// jwt配置
        /// </summary>
        /// <param name="services"></param>
        /// <param name="configuration"></param>
        /// <returns></returns>
        public static IServiceCollection AddJwtConfig(this IServiceCollection services, IConfiguration configuration)
        {
            IConfigurationSection configSection = configuration.GetSection("JwtSettings");
            JwtSettings config = configSection.Get<JwtSettings>();

            services.AddAuthentication(options =>
            {
                //认证middleware配置
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
           .AddJwtBearer(o =>
           {
               o.RequireHttpsMetadata = false;
               o.SaveToken = true;

               //主要是jwt  token参数设置
               o.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
               {
                   //Token颁发机构
                   ValidIssuer = config.Issuer,
                
                   //颁发给谁
                   ValidAudience = config.Audience,
                   //这里的key要进行加密，需要引用Microsoft.IdentityModel.Tokens
                   IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config.SecretKey)),
                   ValidateIssuerSigningKey = true,
                   //是否验证Token有效期，使用当前时间与Token的Claims中的NotBefore和Expires对比
                   ValidateLifetime = true,//是否验证失效时间
                                           ////允许的服务器时间偏移量
                                           //ClockSkew=TimeSpan.Zero
               };
           });
            return services;
        }


        /// <summary>
        /// 添加swagger
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddSwagger(this IServiceCollection services)
        {
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Version = "v1", Title = "Zyiz.net系统WebApi" });

                //jwt授权--start
                //启用auth支持
                
                var bearerScheme = new OpenApiSecurityScheme
                {
                    Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
                    Name = "Authorization",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.ApiKey
                };

                c.AddSecurityDefinition("Bearer", bearerScheme);

                c.AddSecurityRequirement(new OpenApiSecurityRequirement()
                {
                    { bearerScheme, new List<string>()}

                });

                //jwt授权----end

                var dir = new DirectoryInfo(AppContext.BaseDirectory);
                foreach (FileInfo file in dir.EnumerateFiles("*.xml"))
                {
                    c.IncludeXmlComments(file.FullName);
                }
            });

            return services;
        }


        //public static IServiceCollection AddBus(this IServiceCollection services, IConfiguration configuration)
        //{
        //    return services.ConfigureMq(configuration, MqNames.TemplateMq) 
        //                   .AddSingleton(provider => RabbitHutch.CreateBus(configuration.GetConnectionString("RabbitMq")))
        //                   .AddHostedService<BusHostedService>();
        //}

        //public static IServiceCollection ConfigureMq(this IServiceCollection services, IConfiguration configuration, string name)
        //    => services.Configure<MqConfiguration>(name, configuration.GetSection(name));


            /// <summary>
            /// 自动注册服务
            /// </summary>
            /// <param name="applicationLeftTime"></param>
            /// <param name="configuration"></param>
        public static void  ConsulRegister(IHostApplicationLifetime applicationLeftTime,IConfiguration configuration)
        {
            string  globalguid = Guid.NewGuid().ToString("N");

            ConsulRegConfig consulConfig = configuration.GetSection("ConsulConfig").Get<ConsulRegConfig>();

            //程序启动时候注册
            applicationLeftTime.ApplicationStarted.Register(() =>
            {
                using (var consulClient = new ConsulClient(c =>
                {
                    c.Address = new Uri(consulConfig.ConsulAddress);
                    c.Token = consulConfig.Token;

                }))
                {
                    int times = 0;
                    while (times++ < 10)
                    {
                        try
                        {
                            //获取接口所在服务器的ip地址
                            var ipaddress = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()
                                                                            .Select(p => p.GetIPProperties())
                                                                            .SelectMany(p => p.UnicastAddresses)
                                                                            .Where(p => p.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork && !System.Net.IPAddress.IsLoopback(p.Address))
                                                                            .Select(p => p.Address.ToString()).ToArray().First();
                            AgentServiceRegistration asr = new AgentServiceRegistration
                            {
                                Address = ipaddress,
                                Port =  consulConfig.ServicePort,
                                ID = globalguid,
                                Name =  consulConfig.ServiceName,
                                Check = new AgentServiceCheck
                                {
                                    DeregisterCriticalServiceAfter = TimeSpan.FromMinutes(120),
                                    HTTP = $"http://{ipaddress}:{ consulConfig.ServicePort}/api/Health/POk",//检查的地址
                                    Interval = TimeSpan.FromSeconds(30),//服务健康检查间隔
                                    Timeout = TimeSpan.FromSeconds(10),//检查超时的时间
                                },
                            };
                            var task = consulClient.Agent.ServiceRegister(asr);
                            task.Wait();
                            Console.WriteLine($"服务注册结果：{task.Result.StatusCode.ToString()}");

                            if (task.Result.StatusCode == System.Net.HttpStatusCode.OK)
                            {
                                break;
                            }
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"服务注册失败:{ex.ToString()}");
                        }

                        Thread.Sleep(times * 500);
                    }
                }
            });

            //程序退出注销服务
            applicationLeftTime.ApplicationStopping.Register(() =>
            {
                using (var consulClient = new ConsulClient(c =>
                {
                    c.Address = new Uri(consulConfig.ConsulAddress);
                    c.Token = consulConfig.Token;

                }))
                {
                    Console.WriteLine("应用退出，开始从consul注销");
                    consulClient.Agent.ServiceDeregister(globalguid).Wait();
                }
            });


        }

    }
}
